package com.learn.springboot.service.utils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author suzheng
 * @date 2024-05-16
 **/
@Slf4j
public class JacksonUtil {

        private static ObjectMapper customObjectMapper;

        static {
            Jackson2ObjectMapperFactoryBean objectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();
            Object[] featuresToDisable = new Object[]{
                    com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
                    com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS
            };
            objectMapperFactoryBean.setFeaturesToDisable(featuresToDisable);
            Object[] featuresToEnable = new Object[]{
                    com.fasterxml.jackson.databind.SerializationFeature.CLOSE_CLOSEABLE};
            objectMapperFactoryBean.setFeaturesToEnable(featuresToEnable);
            objectMapperFactoryBean.setDateFormat(DateUtil.newSimpleFormat(DatePattern.NORM_DATETIME_PATTERN));
            objectMapperFactoryBean.afterPropertiesSet();
            customObjectMapper = objectMapperFactoryBean.getObject();
        }

        /**
         * 获取泛型的Collection Type
         *
         * @param collectionClass 泛型的Collection
         * @param elementClasses  元素类
         * @return JavaType Java类型
         * @since 1.0
         */
        private static JavaType getCollectionType(Class<?> collectionClass,
                Class<?>... elementClasses) {
            return constructParametrizedType(collectionClass, collectionClass,
                    elementClasses);
        }

        /**
         * 获取泛型的Type
         * @param parametrized
         * @param parametersFor
         * @param parameterClasses
         * @return
         */
        public static JavaType constructParametrizedType(Class<?> parametrized, Class<?> parametersFor,
                Class<?>... parameterClasses) {
            return JacksonUtil.customObjectMapper.getTypeFactory().constructParametrizedType(parametrized, parametersFor,
                    parameterClasses);
        }

        /**
         * 获取类型构造器
         * @return
         */
        public static TypeFactory getTypeFactory(){
            return JacksonUtil.customObjectMapper.getTypeFactory();
        }

        /**
         * 转换集合类型
         *
         * @param jsonString
         * @param clazz
         * @return
         */
        public static <T> List<T> convertList(String jsonString, Class<T> clazz) {
            if (jsonString != null && !"".equals(jsonString)) {
                JavaType javaType = getCollectionType(ArrayList.class, clazz);
                List<T> list = null;
                try {
                    list = JacksonUtil.customObjectMapper.readValue(jsonString, javaType);
                } catch (Throwable e) {
//				e.printStackTrace();
                    log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
                }
                return list;
            }

            return null;
        }

        /**
         * 转换map类型
         *
         * @param jsonString
         * @return
         */
        public static Map<String, Object> convertMap(String jsonString) {

            if (jsonString != null && !"".equals(jsonString)) {
                JavaType javaType = getCollectionType(HashMap.class, String.class, Object.class);
                try {
                    return JacksonUtil.customObjectMapper.readValue(jsonString, javaType);
                } catch (Throwable e) {
//				e.printStackTrace();
                    log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
                }
            }

            return null;
        }

        /**
         * 对象序列化
         *
         * @param obj 需要序列化的对象
         * @return 返回json字符串
         */
        public static String toJson(Object obj) {
            try {
                return JacksonUtil.customObjectMapper.writeValueAsString(obj);
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }
            return "";
        }

        /**
         * 对象序列化
         *
         * @param obj 需要序列化的对象
         * @return 返回json 字节数组
         */
        public static byte[] toJsonBytes(Object obj) {
            try {
                return JacksonUtil.customObjectMapper.writeValueAsBytes(obj);
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }
            return new byte[]{};
        }

        /**
         * 将JSON转换成object
         *
         * @param json
         * @param clazz
         * @return
         */
        public static <T> T fromJson(String json, Class<T> clazz) {
            try {
                T t = JacksonUtil.customObjectMapper.readValue(json, clazz);
                return t;
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }

            return null;
        }

        /**
         * 将JSON转换成object
         *
         * @param jsonBytes
         * @param clazz
         * @return
         */
        public static <T> T fromJson(byte[] jsonBytes, Class<T> clazz) {
            try {
                T t = JacksonUtil.customObjectMapper.readValue(jsonBytes, clazz);
                return t;
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }

            return null;
        }

        /**
         * 将JSON转换成object
         *
         * @param json
         * @param valueTypeRef
         * @return
         */
        public static <T> T fromJson(String json, TypeReference<T> valueTypeRef) {
            try {
                T t = JacksonUtil.customObjectMapper.readValue(json, valueTypeRef);
                return t;
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }

            return null;
        }

        /**
         * 将JSON转换成object
         *
         * @param jsonBytes
         * @param valueTypeRef
         * @return
         */
        public static <T> T fromJson(byte[] jsonBytes, TypeReference<T> valueTypeRef) {
            try {
                T t = JacksonUtil.customObjectMapper.readValue(jsonBytes, valueTypeRef);
                return t;
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }

            return null;
        }

        /**
         * 将JSON转换成object
         *
         * @param json
         * @param javaType
         * @return
         */
        public static <T> T fromJson(String json, JavaType javaType) {
            try {
                T t = JacksonUtil.customObjectMapper.readValue(json, javaType);
                return t;
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]", SerialNo.getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }

            return null;
        }

        /**
         * 将JSON转换成object
         *
         * @param jsonBytes
         * @param javaType
         * @return
         */
        public static <T> T fromJson(byte[] jsonBytes, JavaType javaType) {
            try {
                T t = JacksonUtil.customObjectMapper.readValue(jsonBytes, javaType);
                return t;
            } catch (Throwable e) {
//			e.printStackTrace();
                log.error("[{}] [{}] Finish handling .\nSome Exception Occur:[{}]",SerialNo .getSerialNo(), JacksonUtil.class.getName(), ExceptionUtil.getMessage(e));
            }

            return null;
        }

        public void setCustomObjectMapper(ObjectMapper customObjectMapper) {
            JacksonUtil.customObjectMapper = customObjectMapper;
        }

}
